package com.yvon.service.demo.design;

import java.util.HashMap;

/**
 * @author : Yvon
 * @since : 2022-08-17
 */
public class LRUCache<K, V> {

    /**
     * 当前容量
     */
    private int size;

    /**
     * 最大容量
     */
    private int capacity;

    private HashMap<K, CacheNode<K, V>> caches;

    private CacheNode<K, V> header;

    private CacheNode<K, V> tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        this.caches = new HashMap<>();
    }

    public void put(K k, V v) {
        CacheNode<K, V> node = caches.get(k);
        if (null == node) {
            if (caches.size() >= capacity) {
                caches.remove(tail.key);
                removeLast();
            }
            node = new CacheNode<>();
            node.key = k;
        }
        node.value = v;
        moveToFirst(node);
        caches.put(k, node);
    }

    public V get(K k) {
        CacheNode<K, V> node = caches.get(k);
        if (node == null) {
            return null;
        }
        moveToFirst(node);
        return node.value;
    }

    public CacheNode<K, V> remove(K k) {
        CacheNode<K, V> node = caches.get(k);
        if (node != null) {
            if (node.pre != null) {
                node.pre.next = node.next;
            }
            if (node.next != null) {
                node.next.pre = node.pre;
            }
            if (node == header) {
                header = node.next;
            }
            if (tail == node) {
                tail = node.pre;
            }
        }
        return caches.remove(k);
    }

    public void moveToFirst(CacheNode<K, V> node) {
        // 1.如果为空直接返回
        if (node == null) {
            return;
        }
        // 2.如果队列为空，设置为头结点和尾结点
        if (header ==null || tail == null) {
            header = tail = node;
            return;
        }
        // 3.如果是头结点，直接返回
        if (header == node){
            return;
        }
        if(node == tail){
            tail = node.pre;
        }
        // 4.如果不是头结点
        if (node.next != null) {
            node.next.pre = node.pre;
        }
        if (node.pre != null) {
            node.pre.next = node.next;
        }
        // 5.设置头结点
        node.next = header;
        header.pre = node;
        header = node;
        header.pre = null;
    }

    public void removeLast() {
        if (tail != null) {
            tail = tail.pre;
            if (tail != null) {
                tail.pre.next = null;
            }else {
                header = null;
            }
        }
    }

    public void clear() {
        header = null;
        tail = null;
        caches.clear();
    }

    class CacheNode<K, V> {
         K key;

         V value;

         CacheNode<K, V> pre;

         CacheNode<K, V> next;

        public CacheNode(){

        }
    }
}
